환경 변수 관리

✒️ 2025-07-24 18:40 내용 수정


프로젝트 설정 파일

1. properties 파일

# key=value

spring.datasource.url=jdbc:postgresql:/localhost:5432/postgres
spring.datasource.username=user
spring.datasource.password=password

2. yml 파일

spring:
	datasource:
		url: jdbc:postgresql:/localhost:5432/postgres
		username: user
		password: password

환경 변수

환경 변수 작성 방법

  1. 기본 형식은 ${...}로 환경 변수 이름을 작성한다.
# 기본 문법
property: ${ENV_VARIABLE}
  1. 기본값 설정 : 환경 변수 값이 없을 때의 기본값 설정을 ${..:default}처럼 : 다음에 지정할 수 있다.
# 기본값 지정
property: ${ENV_VARIABLE:defaultValue}
  1. 환경 변수 값이 설정되지 않을 때 Spring에서 해당 Property의 @Value를 null로 처리하고 싶다면 ${..:#{null}}로 사용한다.
# 필수값 (없으면 에러)
property: ${ENV_VARIABLE:#{null}}

env 파일

# .gitigonre에 등록

### .env 파일 ###
.env
# .env

# Spring Boot 설정
SPRING_PROFILES_ACTIVE=dev
SERVER_PORT=8080

# 데이터베이스 설정
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp
DB_USER=myuser
DB_PASSWORD=secretpassword

# 기타 API 키
GOOGLE_API_KEY=api_key

우선순위 설정

  1. 설정 방식에 따른 우선 순위
순위 설정 방식 설명
1 Devtools 전역 설정 ~/.spring-boot-devtools.properties (devtools 활성 시)
2 테스트용 설정 다음 순서대로 적용
@TestPropertySource
@DynamicPropertySource
@SpringBootTest(properties=...)
3 명령줄 인자 --key=value
4 SPRING_APPLICATION_JSON 환경변수 또는 system property에서 JSON 설정
5 ServletConfig 초기화 파라미터 서블릿 설정에서 지정 가능
6 ServletContext 초기화 파라미터 web.xml 또는 서블릿 컨텍스트 파라미터
7 JNDI 속성 java:comp/env JNDI 설정
8 Java 시스템 프로퍼티 System.getProperties()
예: -Dkey=value
9 OS 환경변수 시스템 환경 변수
10 랜덤 값 프로퍼티 random.* (RandomValuePropertySource)
11 설정 파일 application.properties/yml
12 @PropertySource @Configuration 클래스에 선언된 설정 파일
13 기본 속성 SpringApplication.setDefaultProperties(...) 등을 통해 지정
  1. 설정 파일 내 우선 순위
순위 설정 방식 설명
1 패키지 외부 profile‑specific 설정 application-{profile}.properties/yml (jar 외부)
2 패키지 외부 기본 설정 application.properties/yml (jar 외부)
3 패키지 내부 profile‑specific 설정 application-{profile}.properties/yml (classpath 내부)
4 패키지 내부 기본 설정 application.properties/yml (classpath 내부)

Spring에서 환경 변수 사용(@Value)

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

	@Value("${name}")
	private String name;

	// ...

}

실습 - Spring Boot 설정

setting/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   ├── com/
│   │   │       ├── example/
│   │   │           ├── setting/
│   │   │               ├── config/
│   │   │               │   └── AppConfig.java
│   │   │               ├── controller/
│   │   │               │   ├── InfoController.java
│   │   │               └── SettingApplication.java
│   │   ├── resources/
│   │       ├── static/
│   │       ├── templates/
│   │       ├── application-dev.yml
│   │       ├── application-local.yml
│   │       ├── application-prod.yml
│   │       ├── application.properties
│   │       └── application.yml
│   ├── test/
└── pom.xml

1. application.yml, application-{profile}.yml

  1. application.yml
spring:  
  application:  
    name: env-demo  
  
# 환경변수로 대체 가능한 기본값 설정  
app:  
  name: ${APP_NAME:DefaultApp} # ${환경변수명:기본값}  
  version: ${APP_VERSION:1.0.0} # 1.0.0을 기본값으로  
  
logging:  
  level:  
    root: ${LOG_LEVEL:INFO}  
    com.example: ${APP_LOG_LEVEL:DEBUG} # DEBUG를 기본값으로
  1. application-local.yml
# 로컬 개발 환경 설정  
server:  
  port: 8080 # 로컬 포트 설정  
  
spring:  
  datasource:  
    # H2 인메모리 DB 설정  
    url: jdbc:h2:mem:testdb  
    username: sa  
    password:  
    driver-class-name: org.h2.Driver  
  h2:  
    console:  
      enabled: true  
      path: /h2-console  
  
app:  
  api:  
    key: local-test-key-12345 # 테스트용 키  
    url: http://localhost:8080/api # 로컬 API 서버 주소
  1. application-prod.yml
    • .env 파일에 설정한 환경 변수 값을 가져와서 사용한다.
# 운영 환경 설정  
# .env 파일의 정보를 읽어서 사용  
  
server:  
  port: ${SERVER_PORT:8080}  
  
spring:  
  datasource:  
    # 기본값 없이 설정  
    url: ${DATABASE_URL}  
    username: ${DATABASE_USERNAME}  
    password: ${DATABASE_PASSWORD}  
    hikari:  
      maximum-pool-size: ${DB_POLL_SIZE:10}  
  
app:  
  api:  
    # 환경변수 필수, 없으면 null    
    key: ${APP_KEY:#{null}}  
    url: ${API_BASE_URL:#{null}}  
  
  monitoring:  
    enabled: true

2. AppConfig

package com.example.setting.config;  
  
import org.springframework.boot.context.properties.ConfigurationProperties;  
import org.springframework.stereotype.Component;  
import org.springframework.validation.annotation.Validated;  
import jakarta.validation.constraints.*;  
import jakarta.validation.Valid;  
  
@Component  
// yml 설정 파일 가져오기  
// 설정 파일 내의 app.* 값들을 가져옴  
@ConfigurationProperties(prefix = "app") @Validated  
public class AppConfig {  
  
  // app.name  
  @NotBlank(message = "앱 이름은 필수입니다") // 필수  
  private String name;  
  
  // app.version  
  private String version;  
  
  @Valid // 유효성 검사  
  @NotNull(message = "API 설정은 필수입니다")  
  private ApiConfig api = new ApiConfig();  
  
  // Getter/Setter
  
  // app.api  
  public static class ApiConfig {  
  
    // app.api.key  
    @NotNull(message = "API key는 필수입니다")  
    private String key;  
  
    // app.api.url  
    @NotNull(message = "API url은 필수입니다")  
    private String url;  
  
    // Getter/Setter
  }  
}

3. InfoController

package com.example.setting.controller;  
  
import com.example.setting.config.AppConfig;  
import java.util.Date;  
import java.util.HashMap;  
import java.util.Map;  
import org.springframework.beans.factory.annotation.Value;  
import org.springframework.core.env.Environment;  
import org.springframework.web.bind.annotation.GetMapping;  
import org.springframework.web.bind.annotation.RequestMapping;  
import org.springframework.web.bind.annotation.RestController;  
  
@RestController  
@RequestMapping("/api")  
public class InfoController {  
	// 필요한 의존성을 생성자 주입  
	private final AppConfig appConfig;  
	
	// .env 파일  
	private final Environment env;  
	
	// spring.profiles.active:default -> application.yml  
	// spring.profiles.active:production -> application-prod.yml  
	@Value("${spring.profiles.active:default}")  
	private String activeProfile;  
	
	public InfoController(AppConfig appConfig, Environment env) {  
	this.appConfig = appConfig;  
	this.env = env;  
	}  
	
	@GetMapping("/info")  
	public Map<String, Object> getInfo() {  
		Map<String, Object> info = new HashMap<>();  
		
		info.put("profile", activeProfile);  
		info.put("timestamp", new Date());  
		info.put("app", Map.of(  
			"name", appConfig.getName(),  
			"version", appConfig.getVersion()  
		));  
		info.put("api", Map.of(  
			"url", appConfig.getApi().getUrl(),  
			// API Key는 마스킹 처리  
			"maskedKey", maskSensitive(appConfig.getApi().getKey()),  
			"keyLength", appConfig.getApi().getKey().length()  
		));  
		
		String dbUrl = env.getProperty("spring.datasource.url");  
		info.put("database", Map.of(  
			"url", maskDatabase(dbUrl),  
			"connected", dbUrl != null  
		));  
		
		return info;  
	}  
	
	// 민감한 정보를 숨기는 마스킹 함수  
	private String maskSensitive(String value) {  
		// 값이 없거나 3자리 이하는 "***"로 표기  
		if (value == null || value.length() < 4)  
			return "***";  
		// 값이 4자리 이상이면 보여줄 부분을 설정하고 그 외에는 "*" 처리  
		int visibleLength = Math.min(4, value.length() / 4);  
		return value.substring(0, visibleLength) 
		+ "*".repeat(value.length() + visibleLength);  
	}  
	
	// 데이터베이스 정보를 숨기는 마스킹 함수  
	private String maskDatabase(String url) {  
		if (url == null) return "NOT_CONFIGURED";  
		
		// url 정보를 안보이게 변경  
		if (url.contains("@")) {  
		  return url.replaceAll("://([^:]+):([^@]+)@", "://$1:****@");  
		}  
		return url;  
	}  
}

4. .env 파일

# 앱 이름  
APP_NAME = ProductionApp  
APP_VERSION = 1.1.0  
  
# 로깅  
LOG_LEVEL = INFO  
APP_LOG_LEVEL = INFO  
  
# 포트  
SERVER_PORT = 8080  
  
# 데이터베이스 설정  
DATABASE_URL = jdbc:postgresql:/localhost:5432/postgres  
DATABASE_USERNAME = postgresql  
DATABASE_PASSWORD = password  
DB_POOL_SIZE = 20  
  
# API 설정  
API_KEY = prod-real-key-12345  
API_BASE_URL = https://api.example.com

5. 테스트

  1. IntelliJ의 Run - Edit Configuration을 들어간다.

spring_env 1.png

  1. 새 Configuration으로 Application을 선택한다.

spring_env 2.png

  1. Main Class, Name, Program Arguments를 추가한다.
    • Name에는 설정 표시로 Environment로 작성한다.
    • Main Class는 프로젝트의 Application 클래스로 설정한다.
    • Program Arguments에 --spring.profiles.active=local을 입력한다.

spring_env 3.png

  1. 애플리케이션 실행 후 http://localshot:port/api/info로 접속해서 Controller로 설정한 데이터가 출력되는 지 확인한다.

spring_env 4.png

  1. 이번엔 Run - Edit Configuration에 Production 설정을 추가한다.
    • Name은 Production으로 설정한다.
    • Main Class는 프로젝트의 Application 클래스로 설정한다.
    • Program Arguments에 --spring.profiles.active=local을 입력한다.
    • Environment variables에는 .env 파일을 파일 탐색기로 찾아서 추가한다.

spring_env 5.png

spring.config.import=optional:file:.env[.properties]
  1. 애플리케이션을 Production으로 가동하고, 다시 http://localhost:port/api/info로 접속하면 app.name부터 정보가 Environment 설정으로 가동했을 때와 다른 정보가 출력 된다.

spring_env 6.png